package com.huiquan.management.util;

import com.huiquan.body.service.BodyService;
import com.huiquan.foundation.util.BusinessUtil;
import com.huiquan.framework.utils.FileUtils;
import com.huiquan.icd.job.IcdCodeJob;
import com.huiquan.management.constant.ManagementContants;
import com.huiquan.management.constant.MigrateCode;
import com.huiquan.management.dao.MigrateSwitchDao;
import com.huiquan.management.domain.Migrate;
import com.huiquan.management.service.MigrateService;
import com.huiquan.synonymy.job.SynonymyJob;
import com.huiquan.vocab.job.DyadJob;
import com.huiquan.vocab.service.VocabDyadSymptomService;
import com.huiquan.vocab.service.VocabElementClassifyService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
public class MigrateSwitch {

    protected final Logger LOGGER = LoggerFactory.getLogger(getClass());

    @Autowired
    private MigrateSwitchDao migratewitchDao;
    @Autowired
    private VocabDyadSymptomService vocabDyadSymptomService;
    @Autowired
    private IcdCodeJob icdCodeJob;
    @Autowired
    private VocabElementClassifyService vocabElementClassifyService;
    @Autowired
    private SynonymyJob synonymyJob;
    @Autowired
    private DyadJob dyadJob;
    @Autowired
    private MigrateService migrateService;
    @Autowired
    private BodyService bodyService;

    @Value("${migrate.bak.file.path.pre}")
    private String bakFilePathPre;
    @Value("${migrate.hive.script}")
    private String hiveScript;
    @Value("${migrate.single.file.script}")
    private String singleFileScript;
    @Value("${migrate.batch.file.script}")
    private String batchFileScript;

    public boolean migrateByCode(MigrateCode mc) throws Exception {

        // 根据code获取迁移表数据
        Migrate migrate = migrateService.getMigrateByCode(mc);

        if (MigrateCode.DYAD_SYMPTOM_RELATION_HIVE.equals(mc) || MigrateCode.DYAD_SYMPTOM_RELATION_FILE.equals(mc)) {

            vocabDyadSymptomService.exportSymptomStdDyadTo181();

        } else if (MigrateCode.DISEASE_HOSPITAL.equals(mc)) {

            icdCodeJob.generateIcdCode();

        } else if (MigrateCode.DISEASE_HOSPITAL_OTHER.equals(mc)) {

            icdCodeJob.generateOtherCode();

        } else if (MigrateCode.ELEMENT_SYNONYM.equals(mc)) {

            synonymyJob.generateElement();

        } else if (MigrateCode.DYAD_RULE.equals(mc)) {

            // 导出二元组规则文件
            dyadJob.generateDyadRule2File();

        } else if (MigrateCode.DISEASE_EXTERNAL_TZ.equals(mc)) {
            // 导出滕州疾病数据
            icdCodeJob.generateTZDisease();

        } else if (MigrateCode.ELEMENT_CLASSIFY.equals(mc)) {
            // 导出器官上下级
            vocabElementClassifyService.generateClassify();

        } else if (MigrateCode.BODY_ORGAN.equals(mc) || MigrateCode.BODY_ORGAN_HIVE.equals(mc)) {
            // 导出人体图器官文件
            bodyService.generateBodyOrgan();
        } else if (MigrateCode.BODY_ORGAN_SYMPTOM.equals(mc)) {
            // 导出人体图器官症状文件
            bodyService.generateBodyOrganSymptom();
        } else {

            // 备份
            String bakPath = getBakFilePathByCode(mc, true);
            FileUtils.generateFile(bakPath, getContentByCode(mc, migrate));
            // 导出到hive
            if (ManagementContants.MIGRATE_TYPE_HIVE == migrate.getType()) {

                // 调用脚本迁移
                BusinessUtil.excuteShell(new String[]{hiveScript, bakPath, migrate.getLocation()});

            } else if (ManagementContants.MIGRATE_TYPE_FILE == migrate.getType()) {
                // 导出到文件
                // 导出到181文件
                BusinessUtil.excuteShell(new String[]{singleFileScript, bakPath, migrate.getLocation()});

            }
        }

        // 删除30天之前的备份文件
        deleteBakFilePathByCode(mc);
        return true;
    }

    /**
     * 描述:获取30天前的日子
     *
     * @return
     */
    public static String getBeforeDate(int numDay) {
        SimpleDateFormat dft = new SimpleDateFormat("yyyyMMdd");
        //获取三十天前日期
        Calendar theCa = Calendar.getInstance();
        theCa.setTime(new Date());
        theCa.add(Calendar.DATE, numDay);
        Date start = theCa.getTime();
        return dft.format(start);
    }

    /**
     * 删除30天之前的备份文件
     *
     * @param mc
     */
    private void deleteBakFilePathByCode(MigrateCode mc) {
        // 根据编码获取备份文件夹名称
        String[] codeNameSplit = mc.name().split("_", 2);
        String moduleName = codeNameSplit[0];

        String bakFilePath = bakFilePathPre + File.separator + moduleName.toLowerCase();
        if (codeNameSplit.length > 1) {
            bakFilePath += File.separator + codeNameSplit[1].toLowerCase();
        }
        // 备份文件夹
        File bakFileMk = new File(bakFilePath);
        if (bakFileMk.exists() && bakFileMk.isFile()) {
            // 如果这个路径是个文件则报错
            LOGGER.error("数据迁移的备份文件夹是一个文件夹！");
            throw new RuntimeException("系统错误：数据迁移的备份文件夹是一个文件夹！");
        } else if (bakFileMk.exists()) {
            // 获取该文件夹下的文件或者文件夹
            File[] files = bakFileMk.listFiles();
            // 获取30天前的日期
            String lastMonStr = getBeforeDate(-30);
            int lastMonInt = Integer.parseInt(lastMonStr);
            if (files != null) {
                for (File file : files) {
                    if (StringUtils.isNumeric(file.getName().substring(0, 8))) {
                        int fileDay = Integer.parseInt(file.getName().substring(0, 8));
                        if (fileDay < lastMonInt) {
                            if (file.exists()) {
                                FileUtils.delete(file.getAbsolutePath());
                            }
                        }
                    }

                }
            }
        }
    }


    /**
     * 根据迁移编码获取本地备份文件地址，并将该地址初始化文件或文件夹
     *
     * @param mc           迁移编码
     * @param isSingleFile 是否单一文件，是则返回文件路径，否则返回文件夹路径
     * @return
     */
    private String getBakFilePathByCode(MigrateCode mc, boolean isSingleFile) throws Exception {

        // 根据编码获取备份文件夹名称
        String[] codeNameSplit = mc.name().split("_", 2);
        String moduleName = codeNameSplit[0];

        String bakFilePath = bakFilePathPre + File.separator + moduleName.toLowerCase();
        if (codeNameSplit.length > 1) {
            bakFilePath += File.separator + codeNameSplit[1].toLowerCase();
        }

        // 初始化备份文件夹
        File bakFileDict = new File(bakFilePath);
        if (bakFileDict.exists()) {
            if (bakFileDict.isFile()) {
                // 如果这个路径是个文件则报错
                LOGGER.error("数据迁移的备份文件夹路径是一个文件！");
                throw new RuntimeException("系统错误：数据迁移的备份文件夹路径是一个文件");
            }
        } else {
            // 如果该文件夹不存在，则创建
            bakFileDict.mkdirs();
        }

        // 获取当前日期
        String todayStr = new SimpleDateFormat("yyyyMMdd").format(new Date());

        // 获取当前不存在的一个备份路径
        bakFilePath += File.separator + todayStr;
        File bakFile = new File(bakFilePath);
        int i = 1;
        while (bakFile.exists()) {
            bakFile = new File(bakFilePath + "_" + i++);
        }

        // 根据是否单一文件来返回文件或文件夹
        if (isSingleFile) {
            bakFile.createNewFile();
        } else {
            bakFile.mkdirs();
        }

        return bakFile.getAbsolutePath();
    }

    private String getContentByCode(MigrateCode mc, Migrate migrate) {

        // 校验分隔符
        String sep = migrate.getSep();
        if (sep == null || sep.isEmpty()) {
            LOGGER.error("数据迁移的分隔符未初始化：" + mc.name());
            throw new RuntimeException("数据迁移的分隔符未初始化：" + mc.name());
        }

        StringBuffer result = new StringBuffer();

        List<Map<String, Object>> datas = migratewitchDao.retrieveMigrateData(mc);

        if (!datas.isEmpty()) {
            Set<String> keySet = datas.get(0).keySet();

            if (datas != null && !datas.isEmpty()) {
                if (mc.name().indexOf("NEW_TRAIN") > -1) {
                    String sid = "";
                    for (Map<String, Object> data : datas) {
                        // 如果sid更改了则添加一个空行
                        if (!sid.equals(data.get("sid").toString())) {
                            if (!sid.equals("")) {
                                result.append("\n");
                            }
                            sid = data.get("sid").toString();
                        }
                        result.append(data.get("vocabulary").toString().trim());
                        result.append(ManagementContants.migrateSepValue.get(sep));
                        result.append(data.get("characteristic"));
                        result.append(ManagementContants.migrateSepValue.get(sep));
                        result.append(data.get("property"));
                        if (mc.name().indexOf("NEW_TRAIN_BME") > -1) {
                            result.append(ManagementContants.migrateSepValue.get(sep));
                            result.append(data.get("position1").toString() + data.get("position2"));
                        }
                        result.append("\n");
                    }

                } else {
                    // 获取参数个数
                    int paramCount = 0;
                    while (keySet.contains("r" + (paramCount + 1))) {
                        paramCount++;
                    }

                    if (paramCount != keySet.size()) {
                        LOGGER.error("数据迁移的结果集参数个数有误：" + mc.name());
                        throw new RuntimeException("数据迁移的结果集参数个数有误：" + mc.name());
                    }

                    // 根据约定好的参数排序、分隔符将结果集拼凑为字符串
                    for (Map<String, Object> data : datas) {
                        for (int i = 1; i <= paramCount; i++) {
                            result.append(data.get("r" + i));
                            if (i != paramCount) {
                                result.append(ManagementContants.migrateSepValue.get(sep));
                            }
                        }
                        result.append("\n");
                    }
                }
            }
        }

        return result.toString();
    }
}
